/*
 * Copyright (C) 2013 Daniel Treffenstädt <daniel@treffenstaedt.de>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301  USA
 */

#ifndef O_OBJECT_H
#define O_OBJECT_H

#include "../OGlobal.h"
#include "OCallback.h"

#include <QHash>
#include <QList>


#include <unordered_set>

#include "OQueue.h"

O_START_NAMESPACE

class ThreadLoop;

class Bar {};

class O_EXPORT Object
{
private:
	QHash<void (Bar::*)(), void*>				m_functors;
	QList<Object*>								m_children;

	Object*										m_parent;

	Queue<std::function<void()> >				m_callbacks;

	static std::unordered_set<Object*>			m_objects;

	ThreadLoop									*m_thread;

public:
	Object();
	Object(Object* parent);

	virtual ~Object();

	void moveToThread(ThreadLoop *t);

	Object* parent();
	bool hasParent();
	void setParent(Object* o);
	void removeParent();

	bool addChild(Object* o);
	bool hasChild(Object* o);
	Object* getChild(int index);
	bool removeChild(int index);
	bool removeChild(Object* o);

	int children();

	Object* operator[] (int index);

	template <typename C, typename T, typename... P> void connect(void (C::*sender)(P...), T* obj, void (T::*receiver)(P...))
	{
		m_functors[(void (Bar::*)()) sender]		= (void*) new Callback<T, P...>(obj, receiver);
	}

	template <typename C, typename... P> void disconnect(void (C::*sender)(P...))
	{
		m_functors.remove((void (Bar::*)()) sender);
	}

	static void callEventsS();

	void callEventsD();

protected:
	template <typename C, typename... P> void sendEvent(void (C::*sender)(P...), P... params)
	{
		if (m_functors.contains((void (Bar::*)()) sender))
		{
			std::function<void()> f	= (*static_cast<Functor<P...>*>(m_functors[(void (Bar::*)()) sender]))(params...);
			m_callbacks.push(f);
		}
	}
};

O_END_NAMESPACE

#endif // O_OBJECT_H
